/**
 * Desc :
 * Wiki :
 * User : peimingxiao_dxm
 * Date : 2022/11/29 09:39
 */

package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sync"
	"syscall"
)

func main() {
	err := CopyFile2("/Users/dxm/Desktop/web/go/src/go-study/2022-11-28-20.log", "xxxxxxx.txt")
	if err != nil {
		log.Fatalf("copy file failed, err:%+v", err)
	}
}

func goWriteFile() {
	//  1、使用 write 和 writeString
	file, err := os.OpenFile("xxxx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer file.Close()

	str := "hello 沙河\n"
	n, err := file.Write([]byte(str))
	if err != nil || n <= 0 {
		log.Fatalf("write file failed, err:%+v", err)
	}
	n, err = file.WriteString(str)
	if err != nil || n <= 0 {
		log.Fatalf("write file failed, err:%+v", err)
	}

	// 2、bufio.NewWrite
	openFile, err := os.OpenFile("xxxx.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer file.Close()
	writer := bufio.NewWriter(openFile)
	n, err = writer.WriteString(str)
	if err != nil || n <= 0 {
		log.Fatalf("write file failed, err:%+v", err)
	}
	err = writer.Flush()
	if err != nil {
		log.Fatalf("write file failed, err:%+v", err)
	}

	// 3、ioutil.WriteFile
	err = ioutil.WriteFile("xxxx.txt", []byte(str), 0666)
	if err != nil {
		log.Fatalf("write file failed, err:%+v", err)
	}
}

func readFileByBytes() {
	// 1、使用 os 库按字节数读取文件
	open, err := os.Open("/Users/dxm/Desktop/web/go/src/go-study/2022-11-28-20.log")
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer open.Close()

	var content string
	tmp := make([]byte, 128)
	for true {
		n, err := open.Read(tmp)
		if n == 0 {
			break
		}
		if err != nil {
			log.Fatalf("read file failed, err:%+v", err)
		}
		content += string(tmp[:n])
	}
	fmt.Println(content)

	// 2、使用 syscall 库按字节数读取文件
	fd, err := syscall.Open("/Users/dxm/Desktop/web/go/src/go-study/2022-11-28-20.log", syscall.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer syscall.Close(fd)

	group := sync.WaitGroup{}
	group.Add(2)
	dataChan := make(chan []byte) // 初始化一个 byte 类型的通道
	go func() {
		defer group.Done()
		for true {
			bytes := make([]byte, 1024)
			read, err := syscall.Read(fd, bytes)
			if read == 0 {
				break
			}
			if err != nil {
				log.Fatalf("read file failed, err:%+v", err)
			}
			dataChan <- bytes
		}
		close(dataChan)
	}()

	go func() {
		defer group.Done()
		for true {

			select {
			case bytes, ok := <-dataChan:
				if !ok {
					return
				}
				fmt.Println(string(bytes))
			default:

			}
		}
	}()

	group.Wait()
}

func goAllFile() {
	filePath := "/Users/dxm/Desktop/web/go/src/go-study/2022-11-28-20.log"
	openFileErrLogTpl := "open file failed, err:%+v"
	readFileErrLogTpl := "read file failed, err:%+v"

	// 1、使用 ioutil.ReadFile 读取 2022-11-28-20.log 整个文件的内容
	file, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatalf(openFileErrLogTpl, err)
	}
	fmt.Println(string(file))

	// 2、使用 os.ReadFile 读取 2022-11-28-20.log 整个文件的内容
	// 在 Go1.16 开始，iotuil.ReadFile 就等价于 os.ReadFile，二者完全一致
	//	func ReadFile(filename string) ([]byte, error) {
	//		return os.ReadFile(filename)
	//	}
	readFile, err := os.ReadFile(filePath)
	if err != nil {
		log.Fatalf(openFileErrLogTpl, err)
	}
	fmt.Println(string(readFile))

	// 3、先创建句柄再读取，如果仅是读取，可以使用高级函数 os.Open
	open, err := os.Open(filePath)
	if err != nil {
		log.Fatalf(openFileErrLogTpl, err)
	}
	defer open.Close()
	readAll, err := ioutil.ReadAll(open)
	if err != nil {
		log.Fatalf(readFileErrLogTpl, err)
	}
	fmt.Println(string(readAll))

	// 4、之所以说 os.Open 是高级函数，是因为它只是只读模式的 os.OpenFile
	// func Open(name string) (*File, error) {
	//		return OpenFile(name, O_RDONLY, 0)
	// }
	// 因此，也可以直接使用 os.OpenFile，只是要多加俩个参
	openFile, err := os.OpenFile(filePath, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf(openFileErrLogTpl, err)
	}
	defer openFile.Close()
	all, err := ioutil.ReadAll(openFile)
	if err != nil {
		log.Fatalf(readFileErrLogTpl, err)
	}
	fmt.Println(string(all))
}

func goBufIo() {

	// 使用 bufio.ReadString
	open, err := os.Open("/Users/dxm/Desktop/web/go/src/go-study/2022-11-28-20.log")
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer open.Close()
	reader := bufio.NewReader(open)
	var content string
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			if len(line) > 0 {
				content += line
			}
			break
		}
		if err != nil {
			log.Fatalf("read file failed, err:%+v", err)
		}
		content += line
	}
	fmt.Println(content)

	// 使用 bufio.ReadBytes
	content = ""
	for {
		readBytes, err := reader.ReadBytes('\n')
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("read file failed, err:%+v", err)
		}
		content += string(readBytes)
	}
	fmt.Println(content)
}

func goReadFile() {
	file, err := os.Open("../2022-11-28-20.log")
	if err != nil {
		log.Fatalf("open file failed, err:%+v", err)
	}
	defer file.Close()

	var content []byte
	tmp := make([]byte, 128)
	for {
		n, err := file.Read(tmp)
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("read file failed, err:%+v", err)
		}
		content = append(content, tmp[:n]...)
	}
	fmt.Println(string(content))
}

func goOpenFile() {
	file, err := os.Open("/Users/dxm/Desktop/web/go/src/go-study/operation_file/main.go")
	if err != nil {
		fmt.Println("open file failed!,err：", err)
		return
	}
	defer file.Close()
	fmt.Printf("%+v", 111)
}
